﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using WmsService.AOP;
using WmsService.Derived;
using WmsService.Exceptions;
using WmsService.Generate;
using WmsService.In;
using WmsService.Util;

namespace WmsService.BusinessLogic
{
    /// <summary>
    /// 入库逻辑接口
    /// </summary>
    public interface IInStoreBillLogic
    {
        //[ServiceImplCallHandler]
        InStoreBillWrap GetInStoreBillWrap(string billID);

        [ValidateTokenCallHandler]
        void SaveInStoreBillWrap(InStoreBillWrap inStoreBillWrap);

        [ValidateTokenCallHandler]
        void AffirmInStoreBill(string billID, DateTime? inBillDate);

        [ValidateTokenCallHandler]
        void AffirmInStoreBillInvoice(string billID, DateTime? inStoreBillInvoiceDate);

        //[ServiceImplCallHandler]
        string GetInStoreBillID();

        InStoreBill GetInStoreBill(string billID);

        /// <summary>
        /// 从非正常出库单（借用、检修等）中导入到入库单
        /// </summary>
        /// <param name="outStorebillID"></param>
        /// <returns></returns>
        [ValidateTokenCallHandler]
        string ImportInStoreBillFromOutStoreBill(string outStorebillID);

        /// <summary>
        /// 查询非正常的出库单（借用、检修等）
        /// </summary>
        /// <param name="condition"></param>
        /// <returns></returns>
        List<OutStoreBill> GetAbnormalOutStoreBill(string condition);

        /// <summary>
        /// 获取配置中出库代码和入库代码对应键值对列表，然后单独取出出库代码列表
        /// </summary>
        /// <returns></returns>
        List<String> GetAbnormalInStoreBillCodes();

        /// <summary>
        /// 从非正常出库单（借用、检修等）中导入到入库单
        /// </summary>
        /// <param name="outStorebillID"></param>
        /// <returns></returns>
        InStoreBillWrap ImportInStoreBillFromOutStoreBill2(string outStorebillID);
    }

    public class InStoreBillLogicImpl : LogicBase, IInStoreBillLogic
    {
        //入库部分
        public In.InStoreBillWrap GetInStoreBillWrap(string billID)
        {
            try
            {
                var billWrap = new InStoreBillWrap();
                var ctx = Factory.ContextFactory.Create();
                var q = from c in ctx.InStoreBill
                        where c.BillID == billID
                        select c;  
                var inStoreBill = q.FirstOrDefault();
                if (inStoreBill == null)
                {
                    Exceptions.ExceptionHandler.ThrowException("不存在入库单：" + billID);
                }
              
                ctx.Detach(inStoreBill);
                billWrap.PInStoreBill = inStoreBill;
                var q2 = from c in ctx.InStoreBillDtl
                         orderby c.Idx ascending 
                         where c.BillID == billID
                         select c;
                billWrap.PInStoreBillDtl = q2.ToList();
                foreach (var dtl in billWrap.PInStoreBillDtl)
                {
                    ctx.Detach(dtl);
                }

                billWrap.PInvoiceBillInStoreBill = this.GetExtendInvoiceBillInStoreBillsByCondition(String.Format(" and InStoreBillID='{0}'", billID));

                return billWrap;
            }
            catch (Exception ex)
            {
                ExceptionHandler.ThrowException(ex);
                return null;
            }
        }

        public void SaveInStoreBillWrap(In.InStoreBillWrap inStoreBillWrap)
        {
            try
            {
                if(String.IsNullOrEmpty(inStoreBillWrap.PInStoreBill.ProviderCode))
                {
                    ExceptionHandler.ThrowException("供应商为空的入库单不能保存！");
                }

                if (inStoreBillWrap.PInStoreBill.BillState != Constant.BillStateDraft)
                {
                    ExceptionHandler.ThrowException("非草稿状态的入库单不能保存：" + inStoreBillWrap.PInStoreBill.BillID);
                }

                var ctx = Factory.ContextFactory.Create();
                if (inStoreBillWrap.PInStoreBill.WcfEntityState == EntityState.Added)
                {
                    inStoreBillWrap.PInStoreBill.CREATETIME = DateTime.Now;
                    inStoreBillWrap.PInStoreBill.UPDATETIME = DateTime.Now;
                    inStoreBillWrap.PInStoreBill.CREATERUSERID = ContextUserID;
                    inStoreBillWrap.PInStoreBill.CREATERNAME = ContextUserName;
                    inStoreBillWrap.PInStoreBill.UPDATERNAME = ContextUserID;
                    //发票未确认先置状态 2010-10-28
                    inStoreBillWrap.PInStoreBill.ConfirmInvoiceFlag = Constant.ConfirmInvoiceFlagNo;
                }
                else
                {
                    inStoreBillWrap.PInStoreBill.UPDATETIME = DateTime.Now;
                    inStoreBillWrap.PInStoreBill.UPDATERNAME = ContextUserID;
                }
                ctx.AddToInStoreBill(inStoreBillWrap.PInStoreBill);
                ctx.ObjectStateManager.ChangeObjectState(inStoreBillWrap.PInStoreBill, inStoreBillWrap.PInStoreBill.WcfEntityState);

                //以下是明细：

                if (inStoreBillWrap.PInStoreBillDtl != null && inStoreBillWrap.PInStoreBillDtl.Count > 0)
                {
                    //需要持久化的对象列表
                    var storeGoodsPersistList = new List<StoreGoods>();

                    //取最大库存表的编号
                    RowIDControllerBaseFactory baseFactory = new RowIDControllerBaseStoreGoodsFactory();
                    var controller = baseFactory.GetRowIDController();
                   
                    foreach (var inStoreBillDtl in inStoreBillWrap.PInStoreBillDtl)
                    {
                        //if add inStoreBillDtl entity ,then need to insert an entity to storegoods .
                        //get StoreGoods entities

                        StoreGoods storeGoods = null;

                        //是否storeGoods对象是从storeGoodsPersistList中获得
                        //bool storeGoodsInList = false;

                        //新增入库明细记录
                        if (inStoreBillDtl.WcfEntityState == EntityState.Added)
                        {
                            inStoreBillDtl.CREATETIME = DateTime.Now;
                            inStoreBillDtl.UPDATETIME = DateTime.Now;
                            inStoreBillDtl.CREATERUSERID = ContextUserID;
                            inStoreBillDtl.CREATERNAME = ContextUserName;
                            inStoreBillDtl.UPDATERNAME = ContextUserID;

                            foreach (var storeGoodsTmp in storeGoodsPersistList)
                            {
                                if(storeGoodsTmp.NewGoodsCode == inStoreBillDtl.NewGoodsCode)
                                {
                                    storeGoods = storeGoodsTmp;
                                    break;
                                }
                            }
                            if (storeGoods == null)
                            {
                                storeGoods = GetStoreGoods(inStoreBillDtl.NewGoodsCode, inStoreBillDtl.SpecificationType);
                                if (storeGoods != null)
                                {
                                    storeGoodsPersistList.Add(storeGoods);
                                }
                            }
                            //如果没有库存对象，则新增进入
                            if (storeGoods == null)
                            {
                                var dtl = inStoreBillDtl;
                             
                                //定义一个库存对象
                                storeGoods = StoreGoods.CreateStoreGoods(controller.GetNextRowID(), 0, 0, 0, 0, 0, 0);
                                storeGoods.CREATETIME = DateTime.Now;
                                storeGoods.CREATERNAME = ContextUserID;
                                storeGoods.ISVALID = Constant.IsValidTrue;
                                storeGoods.UPDATERNAME = ContextUserID;
                                storeGoods.UPDATETIME = DateTime.Now;
                                storeGoods.UnitCode = dtl.UnitCode;
                                storeGoods.UnitName = dtl.UnitName;
                                storeGoods.TaxRate = (decimal)0.17;
                                storeGoods.StoreTypeCode = dtl.StoreTypeCode;
                                storeGoods.StoreTypeName = dtl.StoreTypeName;
                                storeGoods.NewGoodsCode = dtl.NewGoodsCode;
                                storeGoods.NewGoodsName = dtl.NewGoodsName;
                                storeGoods.OldGoodsCode = dtl.OldGoodsCode;
                                storeGoods.SpecificationType = dtl.SpecificationType;

                                storeGoods.WcfEntityState = EntityState.Added;

                                //2010-11-03，注意，新增的时候就修改库存数据
                                //新增为则直接将明细的数量赋给库存对象了
                                storeGoods.Quantity = inStoreBillDtl.Quantity;

                                //2010-11-17，库位 added by henrik
                                storeGoods.ExtVarChar8 = inStoreBillDtl.StoreLocation;

                                storeGoodsPersistList.Add(storeGoods);

                                //ctx.AddToStoreGoods(storeGoods);
                                //ctx.ObjectStateManager.ChangeObjectState(storeGoods,EntityState.Added);
                            }
                            else// 如果存在库存对象，则修改
                            {
                                storeGoods.Quantity += (inStoreBillDtl.Quantity );

                                //2010-11-17，库位 added by henrik
                                //如果库位为空，则加入，主要是为了保证以前的数据，以前如果没有库位，如果不放入，则可能导致永远没有库位。
                                if (String.IsNullOrEmpty(storeGoods.ExtVarChar8))
                                {
                                    storeGoods.ExtVarChar8 = inStoreBillDtl.StoreLocation;
                                }
                            
                                //ctx.AddToStoreGoods(storeGoods);
                                //ctx.ObjectStateManager.ChangeObjectState(storeGoods, EntityState.Modified);
                            }
                        }
                        else//修改入库明细
                        {
                            //数据库实际入库明细对象
                            var dbInStoreBillDtl = this.GetInStoreBillDtl(inStoreBillDtl.BillDtlID);
                           
                            //如果修改了货物代码
                            if (dbInStoreBillDtl.NewGoodsCode != inStoreBillDtl.NewGoodsCode)
                            {
                                ExceptionHandler.ThrowException(string.Format("该入库明细：物料代码{0}，规格{1}的供应商不能修改！ ",
                                                                                inStoreBillDtl.NewGoodsCode,
                                                                                inStoreBillDtl.SpecificationType));
                            }

                            //if ((dbInStoreBillDtl.InvoiceDtlTotalAmountTax ?? 0) > 0)
                            //{
                            //    ExceptionHandler.ThrowException(string.Format("该入库明细：物料代码{0}，规格{1}，由于已经分摊发票，所以不能修改！ ",
                            //                                               inStoreBillDtl.NewGoodsCode,
                            //                                               inStoreBillDtl.SpecificationType));
                            //}

                            //如果分摊了发票，则单价数量金额不能修改，注意，一定不能是客户端传过来的对象的发票分摊金额，
                            //一定要是从db中查询出来的对象
                            //if ((inStoreBillDtl.InvoiceDtlTotalAmountTax ?? 0) > 0)
                            if ((dbInStoreBillDtl.InvoiceDtlTotalAmountTax ?? 0) > 0)
                            {
                                if (dbInStoreBillDtl.Quantity != inStoreBillDtl.Quantity
                                    || dbInStoreBillDtl.PriceTax != inStoreBillDtl.PriceTax
                                    || dbInStoreBillDtl.PriceNotTax != inStoreBillDtl.PriceNotTax
                                    || dbInStoreBillDtl.AmountTax != inStoreBillDtl.AmountTax
                                    || dbInStoreBillDtl.AmountNotTax != inStoreBillDtl.AmountNotTax)
                                {
                                    ExceptionHandler.ThrowException(string.Format("该入库明细：物料代码{0}，规格{1}已经分摊了发票，不能修改单价、数量、金额！ ",
                                                                                  inStoreBillDtl.NewGoodsCode,
                                                                                  inStoreBillDtl.SpecificationType));
                                }
                            }

                            //以下2个非界面修改属性（只在后台处理）保证和数据库中的字段一致
                            inStoreBillDtl.InvoiceDtlTotalAmountTax = dbInStoreBillDtl.InvoiceDtlTotalAmountTax;
                            inStoreBillDtl.InvoiceNoList = dbInStoreBillDtl.InvoiceNoList;


                            inStoreBillDtl.UPDATETIME = DateTime.Now;
                            inStoreBillDtl.UPDATERNAME = ContextUserID;

                            //逻辑，修改明细的时候，先看该记录的原始数量字段为多少，如果数量变化，则需要修改库存。
                            //2010-11-03，注意，新增的时候就修改库存数据
                            //新增为则直接将明细的数量赋给库存对象了
                            //var storeGoods = GetStoreGoods(inStoreBillDtl.NewGoodsCode, inStoreBillDtl.SpecificationType);

                            //如果两个不对应了，则执行库存修改
                            if (inStoreBillDtl.Quantity != dbInStoreBillDtl.Quantity)
                            {
                                foreach (var storeGoodsTmp in storeGoodsPersistList)
                                {
                                    if (storeGoodsTmp.NewGoodsCode == inStoreBillDtl.NewGoodsCode)
                                    {
                                        storeGoods = storeGoodsTmp;
                                        break;
                                    }
                                }

                                if (storeGoods == null)
                                {
                                    storeGoods = GetStoreGoods(inStoreBillDtl.NewGoodsCode, inStoreBillDtl.SpecificationType);
                                    storeGoodsPersistList.Add(storeGoods);
                                }

                                storeGoods.Quantity += (inStoreBillDtl.Quantity - dbInStoreBillDtl.Quantity);
                        
                                //ctx.AddToStoreGoods(storeGoods);
                                //ctx.ObjectStateManager.ChangeObjectState(storeGoods,EntityState.Modified);
                            }
                        }
                        ctx.AddToInStoreBillDtl(inStoreBillDtl);
                        ctx.ObjectStateManager.ChangeObjectState(inStoreBillDtl, inStoreBillDtl.WcfEntityState);
                    }
                    foreach (StoreGoods store in storeGoodsPersistList)
                    {
                        ctx.AddToStoreGoods(store);
                        ctx.ObjectStateManager.ChangeObjectState(store, store.WcfEntityState);
                    }
                }
                ctx.SaveChanges();
            }
            catch (Exception ex)
            {
                ExceptionHandler.ThrowException(ex);
            }
        }

        /// <summary>
        /// 查询库存对象
        /// </summary>
        /// <param name="newGoodsCode">货物代码</param>
        /// <param name="specificationType">规格</param>
        /// <returns></returns>
        private StoreGoods GetStoreGoods(string newGoodsCode, string specificationType)
        {
             var ctx = Factory.ContextFactory.Create();
            var query = from o in ctx.StoreGoods
                        where o.NewGoodsCode == newGoodsCode
                        && o.SpecificationType == specificationType
                        select o;
            var storeGoods = query.FirstOrDefault();
            if(storeGoods == null)
            {
                //ExceptionHandler.ThrowException(String.Format("库存对象不存在，请联系管理员！物料代码{0}，规格{1}！",newGoodsCode,specificationType));
                return null;
            }
            else
            {
                ctx.Detach(storeGoods);
                storeGoods.WcfEntityState = EntityState.Modified;
                return storeGoods;
            }
        }

        private InStoreBillDtl GetInStoreBillDtl(string billDtlID)
        {
            var ctx = Factory.ContextFactory.Create();
            var query = from o in ctx.InStoreBillDtl
                        where o.BillDtlID == billDtlID
                        select o;
            var inStoreBillDtl = query.FirstOrDefault();
            if (inStoreBillDtl == null)
            {
                //ExceptionHandler.ThrowException(String.Format("入库明细对象不存在，请联系管理员！主键{0}！",billDtlID));
                return null;
            }
            else
            {
                ctx.Detach(inStoreBillDtl);
                return inStoreBillDtl;
            }
        }

        private decimal GetTotalInvoiceBillAmount(string inStoreBillID)
        {
            var ctx = Factory.ContextFactory.Create();
            var q = from o in ctx.InvoiceBillInStoreBill
                    where o.InStoreBillID == inStoreBillID
                    select o;
            var list = q.ToList();
            decimal temp = 0;
            foreach (var invoiceBillInStoreBill in list)
            {
                temp += invoiceBillInStoreBill.PayAmountTax;
            }
            //decimal d1 = q.Sum(o => o.PayAmountTax);
            return temp;
        }

        private decimal GetTotalInStoreBillDtlAmount(string inStoreBillID)
        {
            var ctx = Factory.ContextFactory.Create();
            var q = from o in ctx.InStoreBillDtl
                    where o.BillID == inStoreBillID
                    select o;
            var list = q.ToList();
            decimal temp = 0;
            foreach (var invoiceBillInStoreBill in list)
            {
                temp += invoiceBillInStoreBill.AmountTax;
            }

            //decimal d1 = q.Sum(o => o.AmountTax);
            return temp;
        }

        private bool CheckNeedBindingInvoiceBill(InStoreBill inStoreBill)
        {
            if (inStoreBill == null)
                return false;
            var abnormalInStoreBillCodes = GetAbnormalInStoreBillCodes();
            var q = from o in abnormalInStoreBillCodes
                    where o.Contains(inStoreBill.ExtVarChar1)
                    select o;
            if (q.Count() > 0)
                return false;
            return true;
        }

        public void AffirmInStoreBill(string billID, DateTime? inBillDate)
        {
            try
            {
                var ctx = Factory.ContextFactory.Create();

                var wrap = GetInStoreBillWrap(billID);

                var inStoreBill = wrap.PInStoreBill;
                List<InStoreBillDtl> inStoreBillDtlList = wrap.PInStoreBillDtl;
                if (inStoreBill.BillState != Constant.BillStateDraft)
                {
                    ExceptionHandler.ThrowException("入库单状态为非草稿状态，不能确认入库：" + billID);
                }

                if (inBillDate == null)
                {
                    ExceptionHandler.ThrowException("入库确认日期为空，不能确认入库：" + billID);
                }

                //if (CheckNeedBindingInvoiceBill(inStoreBill))
                //{
                //    //判断，如果需要发票，则需要校验发票总额和明细是否一致
                //    if (GetTotalInvoiceBillAmount(inStoreBill.BillID) !=
                //        GetTotalInStoreBillDtlAmount(inStoreBill.BillID))
                //    {
                //        ExceptionHandler.ThrowException("入库单明细含税金额总额与所分配发票金额之和不一致，不能确认入库：" + billID);
                //    }
                //    var invoiceBillInStoreBills = wrap.PInvoiceBillInStoreBill;
                //    var abstractFactory = LogicFactoryCreator.CreateAbstractFactory();
                //    var invoiceAndPayApplyBillLogic = abstractFactory.CreateInvoiceAndPayApplyBillLogic();
                //    foreach (var extendInvoiceBillInStoreBill in invoiceBillInStoreBills)
                //    {
                //        var invoiceBill = invoiceAndPayApplyBillLogic.GetInvoiceBill(extendInvoiceBillInStoreBill.InvoiceNo);
                //        if (invoiceBill.ProviderCode != inStoreBill.ProviderCode)
                //        {
                //            ExceptionHandler.ThrowException("入库单的供货商和分摊的发票的供应商不一致，不能确认入库，发票：" + invoiceBill.InvoiceNo);
                //        }
                //    }
                //}
                //else
                //{
                //    if (wrap.PInvoiceBillInStoreBill.Count > 0)
                //    {
                //        ExceptionHandler.ThrowException("外出维修/借用等返回入库不能分配发票，请先删除发票后再确认入库：" + billID);
                //    }
                //}

                //取最大库存表的编号
                //var controller = new RowIDController(RowIDType.StoreGoods);
                RowIDControllerBaseFactory baseFactory = new RowIDControllerBaseStoreGoodsFactory();
                var controller = baseFactory.GetRowIDController();
                //循环每一条入库记录))
                foreach (var dtl in inStoreBillDtlList)
                {
                    //如果入库类型不是导入库存，则不允许数量为0
                    if (inStoreBill.ExtVarChar1 != @"DRKC")
                    {
                        if (dtl.Quantity == 0)
                        {
                            Exceptions.ExceptionHandler.ThrowException("入库单明细物料数量不能为零！");
                        }
                    }
                    var query = from o in ctx.StoreGoods
                                where o.NewGoodsCode == dtl.NewGoodsCode
                                && o.SpecificationType == dtl.SpecificationType //0817 added by xiaxilin
                                select o;
                     //定义一个库存对象
                    var storeGoods = query.FirstOrDefault();

                    if (storeGoods == null)
                    {
                        storeGoods = StoreGoods.CreateStoreGoods(controller.GetNextRowID(), 0, 0, 0, 0, 0, 0);
                        storeGoods.CREATETIME = DateTime.Now;
                        storeGoods.CREATERNAME = ContextUserID;
                        storeGoods.ISVALID = Constant.IsValidTrue;
                        storeGoods.UPDATERNAME = ContextUserID;
                        storeGoods.UPDATETIME = DateTime.Now;
                        storeGoods.UnitCode = dtl.UnitCode;
                        storeGoods.UnitName = dtl.UnitName;
                        storeGoods.TaxRate = dtl.TaxRate;
                        storeGoods.StoreTypeCode = dtl.StoreTypeCode;
                        storeGoods.StoreTypeName = dtl.StoreTypeName;
                        storeGoods.Quantity = dtl.Quantity;
                        storeGoods.PriceTax = dtl.PriceTax;
                        storeGoods.PriceNotTax = dtl.PriceNotTax;
                        storeGoods.NewGoodsCode = dtl.NewGoodsCode;
                        storeGoods.NewGoodsName = dtl.NewGoodsName;
                        storeGoods.OldGoodsCode = dtl.OldGoodsCode;

                        //0817 added by xiaxilin
                        storeGoods.SpecificationType = dtl.SpecificationType;

                        //1013 added by xiaxilin
                        //作为供货商代码使用，当入库成功时，将入库单主表的供货商代码和名称都写入库存表，
                        //(接上)覆盖原来数据，当出库时，将这个数据写入到出库单明细中
                        storeGoods.ExtVarChar1 = inStoreBill.ProviderCode;
                        storeGoods.ExtVarChar2 = inStoreBill.ProviderCode;

                        storeGoods.AmountNotTax = dtl.AmountNotTax;
                        storeGoods.AmountTax = dtl.AmountTax;
                        ctx.AddToStoreGoods(storeGoods);
                        ctx.ObjectStateManager.ChangeObjectState(storeGoods, EntityState.Added);
                    }
                    else//如果存在库存对象，该加权平均计算罗
                    {
                        //分离出来
                        ctx.Detach(storeGoods);

                        //2010-11-03 下面一句屏蔽，因为数量在编辑入库单的时候就已经加入了
                        //storeGoods.Quantity = storeGoods.Quantity + dtl.Quantity;

                        storeGoods.AmountNotTax = storeGoods.AmountNotTax + dtl.AmountNotTax;
                        storeGoods.AmountTax = storeGoods.AmountTax + dtl.AmountTax;

                        //1013 added by xiaxilin
                        //作为供货商代码使用，当入库成功时，将入库单主表的供货商代码和名称都写入库存表，
                        //(接上)覆盖原来数据，当出库时，将这个数据写入到出库单明细中
                        //写入最新的供应商信息，其实，供应商有可能不一致，但管理层面到不到这个层面。
                        if (inStoreBill.ProviderCode.Length > 50)
                        {
                            storeGoods.ExtVarChar1 = inStoreBill.ProviderCode.Substring(0, 50);
                        }
                        else
                        {
                            storeGoods.ExtVarChar1 = inStoreBill.ProviderCode;
                        }
                        if (inStoreBill.ProviderName.Length > 50)
                        {
                            storeGoods.ExtVarChar2 = inStoreBill.ProviderName.Substring(0, 50);
                        }
                        else
                        {
                            storeGoods.ExtVarChar2 = inStoreBill.ProviderName;
                        }

                        if (storeGoods.Quantity == 0)
                        {
                            storeGoods.PriceNotTax = dtl.PriceNotTax;
                        }
                        else
                        {
                            storeGoods.PriceNotTax = Math.Round(
                                (decimal) (storeGoods.AmountNotTax/storeGoods.Quantity), 4);
                        }

                        if (storeGoods.Quantity == 0)
                        {
                            storeGoods.PriceTax = dtl.PriceTax;
                        }
                        else
                        {
                            storeGoods.PriceTax = Math.Round((decimal)(storeGoods.AmountTax / storeGoods.Quantity), 2);
                        }

                        if (storeGoods.PriceNotTax == 0)
                        {
                            storeGoods.TaxRate = dtl.TaxRate;
                        }
                        else
                        {
                             storeGoods.TaxRate = Math.Round((decimal)(storeGoods.PriceTax / storeGoods.PriceNotTax - 1), 4);
                        }

                        //2011-02-11加入，主要是将物料代码的信息复制到库存记录上
                        storeGoods.UnitCode = dtl.UnitCode;
                        storeGoods.UnitName = dtl.UnitName;
                        storeGoods.StoreTypeCode = dtl.StoreTypeCode;
                        storeGoods.StoreTypeName = dtl.StoreTypeName;
                        storeGoods.NewGoodsName = dtl.NewGoodsName;
                        storeGoods.OldGoodsCode = dtl.OldGoodsCode;
                        storeGoods.SpecificationType = dtl.SpecificationType;

                        //更新最修修改信息
                        storeGoods.UPDATETIME = DateTime.Now;
                        storeGoods.UPDATERNAME = ContextUserID;
                      
                        //放入上下文中
                        ctx.AddToStoreGoods(storeGoods);
                        ctx.ObjectStateManager.ChangeObjectState(storeGoods, EntityState.Modified);
                    }
                }

                inStoreBill.BillState = Constant.BillStateAffirm;//状态为确认,即已经入库
                //确认入库必须客户传入
                inStoreBill.InBillDate = inBillDate;

                ctx.AddToInStoreBill(inStoreBill);
                ctx.ObjectStateManager.ChangeObjectState(inStoreBill, EntityState.Modified);
                ctx.SaveChanges();
            }
            catch (Exception ex)
            {
                Exceptions.ExceptionHandler.ThrowException(ex);
            }
        }

        public void AffirmInStoreBillInvoice(string billID, DateTime? inStoreBillInvoiceDate)
        {
            try
            {
                var ctx = Factory.ContextFactory.Create();

                var wrap = GetInStoreBillWrap(billID);
                var inStoreBill = wrap.PInStoreBill;
                List<InStoreBillDtl> inStoreBillDtlList = wrap.PInStoreBillDtl;
                if (inStoreBill.BillState != Constant.BillStateAffirm)
                {
                    ExceptionHandler.ThrowException("入库单状态不是入库确认状态，不能确认入库发票：" + billID);
                }

                if (inStoreBill.ConfirmInvoiceFlag != Constant.ConfirmInvoiceFlagNo)
                {
                    ExceptionHandler.ThrowException("入库单已经确认入库发票：" + billID);
                }

                if (inStoreBillInvoiceDate == null)
                {
                    ExceptionHandler.ThrowException("入库发票确认日期为空，不能确认入库发票：" + billID);
                }
                foreach (var inStoreBillDtl in inStoreBillDtlList)
                {
                    if(inStoreBillDtl.AmountTax != (inStoreBillDtl.InvoiceDtlTotalAmountTax??0))
                    {
                        ExceptionHandler.ThrowException("入库明细没有足够的发票来分摊金额，不能确认入库发票：" + inStoreBillDtl.NewGoodsName);
                    }
                }
                inStoreBill.ConfirmInvoiceFlag = Constant.ConfirmInvoiceFlagYes;
                inStoreBill.ConfirmInvoiceDate = inStoreBillInvoiceDate;
                inStoreBill.ConfirmInvoiceID = ContextUserID;
                inStoreBill.ConfirmInvoiceName = ContextUserName;

                ctx.AddToInStoreBill(inStoreBill);
                ctx.ObjectStateManager.ChangeObjectState(inStoreBill, EntityState.Modified);
                ctx.SaveChanges();
            }
            catch (Exception exception)
            {
                Exceptions.ExceptionHandler.ThrowException(exception);
            }
        }

        public string GetInStoreBillID()
        {
            try
            {
                var ctx = Factory.ContextFactory.Create();
                return ctx.ExecuteStoreQuery<String>("select dbo.GetInStoreBillID() as BillID").FirstOrDefault();
            }
            catch (Exception ex)
            {
                Exceptions.ExceptionHandler.ThrowException(ex);
                return null;
            }
        }

        public InStoreBill GetInStoreBill(string billID)
        {
            var ctx = Factory.ContextFactory.Create();
            var q = from i in ctx.InStoreBill
                    where i.BillID == billID
                    select i;
            var inStoreBill = q.FirstOrDefault();
            if(inStoreBill != null)
            {
                ctx.Detach(inStoreBill);
                return inStoreBill;
            }
            return null;
        }

// ReSharper disable MemberCanBeMadeStatic.Local
        private List<ExtendInvoiceBillInStoreBill> GetExtendInvoiceBillInStoreBillsByCondition(string condition)
// ReSharper restore MemberCanBeMadeStatic.Local
        {
            try
            {
                var ctx = Factory.ContextFactory.Create();
                return ctx.ExecuteStoreQuery<ExtendInvoiceBillInStoreBill>("select * from (select a.*,b.AmountTax,b.InStoreBillAmount from dbo.InvoiceBillInStoreBill a,dbo.InvoiceBill b where a.InvoiceNo = b.InvoiceNo) tmp where 1=1 " + condition).ToList();
            }
            catch (Exception ex)
            {
                Exceptions.ExceptionHandler.ThrowException(ex);
                return null;
            }
        }

        /// <summary>
        /// 逻辑：
        /// A:根据出库单号码取出出库单
        /// B:新增一个入库单，赋值出库单的所有信息
        /// C:出库单和入库单的出入库类型要遵守对应关系
        /// 保存入库单，返回入库单单号
        /// </summary>
        /// <param name="outStorebillID"></param>
        /// <returns>入库单单号</returns>
        public string ImportInStoreBillFromOutStoreBill(string outStorebillID)
        {
            //A:
            var logic = LogicFactoryCreator.CreateAbstractFactory().CreateOutStoreBillLogic();
            var outWrap = logic.GetOutStoreBillWrap(outStorebillID);

            //B:
            var inWrap = new InStoreBillWrap();
            string newInStoreBillID = this.GetInStoreBillID();
            inWrap.PInStoreBill = InStoreBill.CreateInStoreBill(newInStoreBillID, DateTime.Now.Date,
                                                                Constant.BillStateDraft);
            //C:
            var outInStoreBillTypes = Util.OutInStoreBillTypeFactory.GetOutInStoreBillTypes();
            var qry = from k in outInStoreBillTypes
                      where k.OutStoreCode == outWrap.POutStoreBill.ExtVarChar1
                      select k;
            var outInStoreBill = qry.FirstOrDefault();
            //如果配置文件中没有对应的出库类型，则异常
            if (outInStoreBill == null)
            {
                ExceptionHandler.ThrowException("配置文件中没有对应的出库类型：" + outWrap.POutStoreBill.ExtVarChar1);
            }
           
            inWrap.PInStoreBill.ExtVarChar1 = outInStoreBill.RelateInStoreCode;
            //分别给入库单主表赋值
            inWrap.PInStoreBill.CheckerID = "";
            inWrap.PInStoreBill.CheckerName = "";
            inWrap.PInStoreBill.ContractNo = "";
            inWrap.PInStoreBill.CREATERNAME = ContextUserName;
            inWrap.PInStoreBill.CREATERUSERID = ContextUserID;
            inWrap.PInStoreBill.CREATETIME = DateTime.Now;
            inWrap.PInStoreBill.InBillDate = DateTime.Now.Date;
            inWrap.PInStoreBill.KeeperID = "";
            inWrap.PInStoreBill.KeeperName = "";

            var customer = OutInStoreBillTypeFactory.GetAbnormalInStoreBillCustomer();

            inWrap.PInStoreBill.ProviderCode = customer.OWNERNO;
            inWrap.PInStoreBill.ProviderName = customer.OWNERNAME;
            inWrap.PInStoreBill.WcfEntityState = EntityState.Added;

            //初始化入库明细
            inWrap.PInStoreBillDtl = new List<InStoreBillDtl>();

            int idx = 0;
            //循环出库单明细，复制到入库单明细
            foreach (var outStoreBillDtl in outWrap.POutStoreBillDtl)
            {
                var inStoreBillDtl = InStoreBillDtl.CreateInStoreBillDtl(
                    Guid.NewGuid().ToString(), newInStoreBillID, ++idx);
                inStoreBillDtl.AmountNotTax = outStoreBillDtl.AmountNotTax;
                inStoreBillDtl.AmountTax = outStoreBillDtl.AmountTax;
                inStoreBillDtl.CREATERNAME = ContextUserName;
                inStoreBillDtl.CREATERUSERID = ContextUserID;
                inStoreBillDtl.CREATETIME = DateTime.Now;
                inStoreBillDtl.NewGoodsCode = outStoreBillDtl.NewGoodsCode;
                inStoreBillDtl.NewGoodsName = outStoreBillDtl.NewGoodsName;
                inStoreBillDtl.OldGoodsCode = outStoreBillDtl.OldGoodsCode;
                inStoreBillDtl.PriceNotTax = outStoreBillDtl.PriceNotTax;
                inStoreBillDtl.PriceTax = outStoreBillDtl.PriceTax;
                inStoreBillDtl.Quantity = outStoreBillDtl.Quantity;
                inStoreBillDtl.SpecificationType = outStoreBillDtl.SpecificationType;
                inStoreBillDtl.StoreTypeCode = outStoreBillDtl.StoreTypeCode;
                inStoreBillDtl.StoreTypeName = outStoreBillDtl.StoreTypeName;
                inStoreBillDtl.TaxRate = outStoreBillDtl.TaxRate;
                inStoreBillDtl.UnitCode = outStoreBillDtl.UnitCode;
                inStoreBillDtl.UnitName = outStoreBillDtl.UnitName;
                inStoreBillDtl.WcfEntityState = EntityState.Added;
                inWrap.PInStoreBillDtl.Add(inStoreBillDtl);
            }

            //初始化发票
            inWrap.PInvoiceBillInStoreBill = new List<ExtendInvoiceBillInStoreBill>();

            //以下开始执行保存，为了事务，所以没有调用wrap自己的方法
            var ctx = Factory.ContextFactory.Create();
            ctx.AddToInStoreBill(inWrap.PInStoreBill);
            ctx.ObjectStateManager.ChangeObjectState(inWrap.PInStoreBill, inWrap.PInStoreBill.WcfEntityState);
            foreach (var inStoreBillDtl in inWrap.PInStoreBillDtl)
            {
                ctx.AddToInStoreBillDtl(inStoreBillDtl);
                ctx.ObjectStateManager.ChangeObjectState(inStoreBillDtl, inStoreBillDtl.WcfEntityState);
            }
            //将出库单的ExtVarChar4字段记录对应的入库单
            outWrap.POutStoreBill.ExtVarChar4 = inWrap.PInStoreBill.BillID;
            ctx.AddToOutStoreBill(outWrap.POutStoreBill);
            ctx.ObjectStateManager.ChangeObjectState(outWrap.POutStoreBill, EntityState.Modified);
            ctx.SaveChanges();
            return newInStoreBillID;
        }

        public InStoreBillWrap ImportInStoreBillFromOutStoreBill2(string outStorebillID)
        {
            //A:
            var logic = LogicFactoryCreator.CreateAbstractFactory().CreateOutStoreBillLogic();
            var outWrap = logic.GetOutStoreBillWrap(outStorebillID);

            //B:
            var inWrap = new InStoreBillWrap();
            string newInStoreBillID = "新入库单";
            inWrap.PInStoreBill = InStoreBill.CreateInStoreBill(newInStoreBillID, DateTime.Now.Date,
                                                                Constant.BillStateDraft);
            //C:
            var outInStoreBillTypes = Util.OutInStoreBillTypeFactory.GetOutInStoreBillTypes();
            var qry = from k in outInStoreBillTypes
                      where k.OutStoreCode == outWrap.POutStoreBill.ExtVarChar1
                      select k;
            var outInStoreBill = qry.FirstOrDefault();
            //如果配置文件中没有对应的出库类型，则异常
            if (outInStoreBill == null)
            {
                ExceptionHandler.ThrowException("配置文件中没有对应的出库类型：" + outWrap.POutStoreBill.ExtVarChar1);
            }

            inWrap.PInStoreBill.ExtVarChar1 = outInStoreBill.RelateInStoreCode;
            //分别给入库单主表赋值
            inWrap.PInStoreBill.CheckerID = "";
            inWrap.PInStoreBill.CheckerName = "";
            inWrap.PInStoreBill.ContractNo = "";
            inWrap.PInStoreBill.CREATERNAME = ContextUserName;
            inWrap.PInStoreBill.CREATERUSERID = ContextUserID;
            inWrap.PInStoreBill.CREATETIME = DateTime.Now;
            inWrap.PInStoreBill.InBillDate = DateTime.Now.Date;
            inWrap.PInStoreBill.KeeperID = "";
            inWrap.PInStoreBill.KeeperName = "";

            var customer = OutInStoreBillTypeFactory.GetAbnormalInStoreBillCustomer();

            inWrap.PInStoreBill.ProviderCode = customer.OWNERNO;
            inWrap.PInStoreBill.ProviderName = customer.OWNERNAME;
            inWrap.PInStoreBill.WcfEntityState = EntityState.Added;

            //初始化入库明细
            inWrap.PInStoreBillDtl = new List<InStoreBillDtl>();

            int idx = 0;
            //循环出库单明细，复制到入库单明细
            foreach (var outStoreBillDtl in outWrap.POutStoreBillDtl)
            {
                var inStoreBillDtl = InStoreBillDtl.CreateInStoreBillDtl(
                    Guid.NewGuid().ToString(), newInStoreBillID, ++idx);
                inStoreBillDtl.AmountNotTax = outStoreBillDtl.AmountNotTax;
                inStoreBillDtl.AmountTax = outStoreBillDtl.AmountTax;
                inStoreBillDtl.CREATERNAME = ContextUserName;
                inStoreBillDtl.CREATERUSERID = ContextUserID;
                inStoreBillDtl.CREATETIME = DateTime.Now;
                inStoreBillDtl.NewGoodsCode = outStoreBillDtl.NewGoodsCode;
                inStoreBillDtl.NewGoodsName = outStoreBillDtl.NewGoodsName;
                inStoreBillDtl.OldGoodsCode = outStoreBillDtl.OldGoodsCode;
                inStoreBillDtl.PriceNotTax = outStoreBillDtl.PriceNotTax;
                inStoreBillDtl.PriceTax = outStoreBillDtl.PriceTax;
                inStoreBillDtl.Quantity = outStoreBillDtl.Quantity;
                inStoreBillDtl.SpecificationType = outStoreBillDtl.SpecificationType;
                inStoreBillDtl.StoreTypeCode = outStoreBillDtl.StoreTypeCode;
                inStoreBillDtl.StoreTypeName = outStoreBillDtl.StoreTypeName;
                inStoreBillDtl.TaxRate = outStoreBillDtl.TaxRate;
                inStoreBillDtl.UnitCode = outStoreBillDtl.UnitCode;
                inStoreBillDtl.UnitName = outStoreBillDtl.UnitName;
                inStoreBillDtl.WcfEntityState = EntityState.Added;
                inWrap.PInStoreBillDtl.Add(inStoreBillDtl);
            }

            //初始化发票
            inWrap.PInvoiceBillInStoreBill =new List<ExtendInvoiceBillInStoreBill>();

            //以下开始执行保存
            var ctx = Factory.ContextFactory.Create();
            //将出库单的ExtVarChar4字段记录对应的入库单
            outWrap.POutStoreBill.ExtVarChar4 = String.Format("导入时间:{0}",DateTime.Now.ToString(@"yyyy-MM-dd HH:mm:ss"));
            ctx.AddToOutStoreBill(outWrap.POutStoreBill);
            ctx.ObjectStateManager.ChangeObjectState(outWrap.POutStoreBill, EntityState.Modified);
            ctx.SaveChanges();
            return inWrap;
        }

        public List<OutStoreBill> GetAbnormalOutStoreBill(string condition)
        {
            var outStoreBillCodes =
                Util.OutInStoreBillTypeFactory.GetOutInStoreBillTypes().Select(type => type.OutStoreCode).ToList();
            //出库单必须是确认出库【1】的，
            //ExtVarChar4（记录对应导入的入库单号码）必须为空或者''，=====此条件已经删除
            //且出库类型必须在outStoreBillCodes中的才能显示出来
            string codesCondition = "  and BillState = '1' and  ExtVarChar1 in   ('*' ";
            foreach (var outStoreBillCode in outStoreBillCodes)
            {
                codesCondition += (",'" + outStoreBillCode + "'");
            }
            codesCondition += ",'*')";
            string sql = "select * from dbo.OutStoreBill where 1=1 " + condition + codesCondition;
            var ctx = Factory.ContextFactory.Create();
            var q = ctx.ExecuteStoreQuery<OutStoreBill>(sql);
            return q.ToList();
        }

        public List<String> GetAbnormalInStoreBillCodes()
        {
            var inStoreBillCodes =
               Util.OutInStoreBillTypeFactory.GetOutInStoreBillTypes().Select(type => type.RelateInStoreCode).ToList();
            return inStoreBillCodes;
        }
    }
}